package com.cavedroid;


import org.everest.simplescores.SimpleScores;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.content.res.Resources;
import android.graphics.ColorMatrix;
import android.graphics.ColorMatrixColorFilter;
import android.net.Uri;
import android.opengl.GLSurfaceView;
import android.os.Bundle;
import android.os.Handler;
import android.os.Vibrator;
import android.preference.PreferenceManager;
import android.util.Log;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.view.View.OnClickListener;
import android.view.View.OnTouchListener;
import android.widget.Button;
import android.widget.TextView;

public class CaveViewActivity extends Activity {
	
	//Site strings
	public static final String DONATION_URL = "http://www.robeverest.com/cavedroid/pay#content";  
    public static final String SITE_URL = "http://www.robeverest.com/cavedroid"; 
    public static final String DONATION_TABLE_URL = "http://www.robeverest.com/android_donations.php";
	
	//Preference strings
    public static final String PREF_PLAY_COUNT = "playCount";
	public static final String PREF_FOG = "fog";
	public static final String PREF_SHORT_CUTOFF = "shortCutoff";
	public static final String PREF_SHOW_WARNING = "showWarning";
	public static final String PREF_CLASSIC_HIGH_SCORE = "hiScore";
	public static final String PREF_TILT_HIGH_SCORE = "tiltHiScore";
	public static final String PREF_DUAL_TILT_HIGH_SCORE = "dualTiltHiScore";
	public static final String PREF_WIREFRAME = "wireframeTunnel";
	public static final String PREF_SCORENINJA_NEVER_ASK = "neverask";
	public static final String PREF_SCORENINJA = "ScoreNinjaPrefs";
	public static final String PREF_INV_VERTICAL = "invVertical";
	public static final String PREF_INV_HORIZONTAL = "invHorizontal";
	
	public GLSurfaceView mGLSurfaceView;
	
	CaveRenderer renderer;
	
	TextView scoreView;
	
	public boolean started = false;
	
	private boolean loadingScores;
	
	public int hiScore;
	
	public int tiltHiScore;
	
	public int dualTiltHiScore;
	
	public int playCount;
	
	public boolean showWarning;
	
	Vibrator vibrator;
	
	LayoutStack layout;
	
	SharedPreferences preferenceManager;
	
	private SimpleScores simpleScores;
	
	public enum GameType { 
		CLASSIC ("", PrivateKeys.CLASSIC.key), 
		TILT ("Tilt", PrivateKeys.TILT.key),
		DUAL_TILT ("DualTilt", PrivateKeys.DUAL_TILT.key);
		
		private final String printable;
		private final String privateKey;
		
		GameType(String printable, String key) {
			this.printable = printable;
			this.privateKey = key;
		}
		
		public String toString() {
			return printable;
		}
	};
	
	public GameType gameType;
	
	@Override
    protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, 
                                WindowManager.LayoutParams.FLAG_FULLSCREEN);
        
        layout = new LayoutStack(this);
        
        preferenceManager = PreferenceManager.getDefaultSharedPreferences(this);
		
        //Load donators if playcount is mod 10
        playCount = preferenceManager.getInt(PREF_PLAY_COUNT, 0);
        
        Log.d("Cavedroid", "Play count: " + playCount);
        
        if (playCount % 10 == 0) {
        	DonationsText.loadDonators(this, DONATION_TABLE_URL);
        }
        
		playCount++;
        
        setContentView(R.layout.main);    
        
        //Setup buttons
        findViewById(R.id.retryButton).setOnClickListener(retryOnClickListener);
        findViewById(R.id.hiScoreButton).setOnClickListener(showScoresOnClickListener);
        findViewById(R.id.mainMenuButton).setOnClickListener(mainMenuOnClickListener);
        findViewById(R.id.payButton).setOnClickListener(payOnClickListener);
        findViewById(R.id.classicModeStartButton).setOnClickListener(touchModeOnClickListener);
        findViewById(R.id.tiltModeStartButton).setOnClickListener(tiltModeOnClickListener);
        findViewById(R.id.dualTiltModeStartButton).setOnClickListener(dualTiltModeOnClickListener);
        findViewById(R.id.goTouchButton).setOnClickListener(startTouchModeOnClickListener);
        findViewById(R.id.goTiltButton).setOnClickListener(startTiltModeOnClickListener);
        findViewById(R.id.goDualTiltButton).setOnClickListener(startDualTiltModeOnClickListener);
        findViewById(R.id.websiteButton).setOnClickListener(websiteOnClickListener);
        findViewById(R.id.settingsButton).setOnClickListener(settingsOnClickListener);
        findViewById(R.id.hiScoresButton).setOnClickListener(hiScoresOnClickListener);
        
        Button payButton = (Button)findViewById(R.id.payButton);
        
        ColorMatrix mat = new ColorMatrix();
        
        mat.setScale(1, 0, 1, 1);
        
        payButton.getBackground().setColorFilter(new ColorMatrixColorFilter(mat));
        
        scoreView = (TextView) findViewById(R.id.score);
        
        vibrator = (Vibrator)getSystemService(Context.VIBRATOR_SERVICE);
        
        simpleScores = new SimpleScores(this);
        
        simpleScores.setTitle("Cavedroid");

		initGLSurface();
		gameStartLayout();
    }
	
	@Override 
	public void onStop() {
		preferenceManager.edit().putInt(PREF_PLAY_COUNT, playCount).commit();
		super.onStop();
	}
	
	private TextView plusScore;
	
	private void getPrefs() {
    	renderer.fog = preferenceManager.getBoolean(PREF_FOG, true);
    	renderer.shortCutoff = preferenceManager.getBoolean(PREF_SHORT_CUTOFF, false);
    	
    	showWarning = preferenceManager.getBoolean(PREF_SHOW_WARNING, true);
    	if (renderer.cave != null) {
    		renderer.cave.wireframeTunnel = preferenceManager.getBoolean(PREF_WIREFRAME, false);
    		if (!showWarning) {
    			renderer.cave.tunnelColor[0] = 0;
    		}
    	}
    	
    	if (gameThread != null) {
    		if (gameType == GameType.TILT || gameType == GameType.DUAL_TILT) {
    			((TiltGameThread)gameThread).verticalDirection = preferenceManager.getBoolean(PREF_INV_VERTICAL, false) ? -1 : 1; 
    		}
    		if (gameType == GameType.DUAL_TILT) {
    			((DualTiltGameThread)gameThread).horizontalDirection = preferenceManager.getBoolean(PREF_INV_HORIZONTAL, true) ? -1 : 1; 
    		}
    	}
    	
    	hiScore = preferenceManager.getInt(PREF_CLASSIC_HIGH_SCORE, 0);
    	
    	tiltHiScore = preferenceManager.getInt(PREF_TILT_HIGH_SCORE, 0);
    	
    	dualTiltHiScore = preferenceManager.getInt(PREF_DUAL_TILT_HIGH_SCORE, 0);
	}

	private void initGLSurface() {	
		renderer = new CaveRenderer();
		
		mGLSurfaceView = (GLSurfaceView) findViewById(R.id.GameSurface);
		
		mGLSurfaceView.setEGLConfigChooser(true);
		mGLSurfaceView.setRenderer(renderer);
		mGLSurfaceView.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY); 
		
		mGLSurfaceView.setOnTouchListener(onTouch);
	}
	
	public void initGameThread(GameThread game) {
		gameThread = null;
		gameThread = game;
		System.gc();
	}
	
	private GameThread gameThread;
	
	Handler uiHandler = new Handler();
	
	//UI events that need to be called by the game thread
	public Runnable showPlus200 = new Runnable() {
		public void run() {
			plusScore.setVisibility(TextView.VISIBLE);
		}
	};
	
	public Runnable hidePlus200 = new Runnable() {
		public void run() {
			plusScore.setVisibility(TextView.INVISIBLE);
		}
	};
	
	public Runnable updateScoreDisplay = new Runnable() {
		public void run() {
			scoreView.setText(gameThread.score + "");
		}
	};
	
	public Runnable endGame = new Runnable() {
		public void run() {
			gameOverLayout();
		}
	};

	//Activity stuff
    @Override
    protected void onResume() {
        super.onResume();
        Log.d("Cavedroid", "Resumed");
        mGLSurfaceView.onResume();
        getPrefs();
        mGLSurfaceView.requestRender();
        if (started) {
        	gameThread.onResume();
        	synchronized (gameThread) { 
        		//gameThread.notify();
        	}
        }
        if (loadingScores) {
        	loadingScores = false;
        	TextView retryText = (TextView)findViewById(R.id.touchToRetry);
    		retryText.setText("");
        }
    }

    @Override
    protected void onPause() {
    	Log.d("Cavedroid", "Paused");
    	if (started) {
        	gameThread.onPause();
        }
        super.onPause();
        mGLSurfaceView.onPause();
        System.gc();
    }
    
    //Simple class to handle touch events
    abstract private class TouchHandler {
    	public abstract boolean touchMethod(int action);
    }
    
    private TouchHandler nilTouchHandler = new TouchHandler() {
    	public boolean touchMethod(int action) {
			return false;
    	}
    };

    public TouchHandler touchHandler = nilTouchHandler;
    
    private TouchHandler caveTouchHandler = new TouchHandler() {
    
    	public boolean touchMethod(int action) {
    		if (action == MotionEvent.ACTION_DOWN) {
    			gameThread.touched = true;	
    		} else if (action == MotionEvent.ACTION_UP){
    			gameThread.touched = false;
    		}
    		return false;
    	}
    };
    
    //Button event handlers
    private OnClickListener startTouchModeOnClickListener = new OnClickListener() {
    	public void onClick(View v) {
    		layout.pop();
    		layout.pop();
    		layout.pop();
    		gameRunningLayout();
    		initGameThread(new GameThread(CaveViewActivity.this));
    		touchHandler = caveTouchHandler;
    		getPrefs();
    		gameThread.start();
    	}
    };
    
    private OnClickListener startTiltModeOnClickListener = new OnClickListener() {
    	public void onClick(View v) {
    		layout.pop();
    		layout.pop();
    		layout.pop();
    		gameRunningLayout();
    		initGameThread(new TiltGameThread(CaveViewActivity.this));
    		getPrefs();
    		gameThread.start();
    	}
    };
    
    private OnClickListener startDualTiltModeOnClickListener = new OnClickListener() {
    	public void onClick(View v) {
    		layout.pop();
    		layout.pop();
    		layout.pop();
    		gameRunningLayout();
    		renderer.cave = new DualCave();
    		initGameThread(new DualTiltGameThread(CaveViewActivity.this));
    		getPrefs();
    		gameThread.start();
    	}
    };
    
    private OnClickListener touchModeOnClickListener = new OnClickListener() {
    	public void onClick(View v) {
    		gameType = GameType.CLASSIC;
    		layout.replace(R.id.touchGameStartMain);
    		layout.push(R.id.startScores);
    		TextView hiScoreText = (TextView)findViewById(R.id.hiScore);
    		hiScoreText.setText(hiScore + "");
    	}
    };
    
    private OnClickListener tiltModeOnClickListener = new OnClickListener() {
    	public void onClick(View v) {
    		gameType = GameType.TILT;
    		layout.replace(R.id.tiltGameStartMain);
    		layout.push(R.id.startScores);
    		TextView hiScoreText = (TextView)findViewById(R.id.hiScore);
    		hiScoreText.setText(tiltHiScore + "");
    	}
    };
    
    private OnClickListener dualTiltModeOnClickListener = new OnClickListener() {
    	public void onClick(View v) {
    		gameType = GameType.DUAL_TILT;
    		layout.replace(R.id.dualTiltGameStartMain);
    		layout.push(R.id.startScores);
    		TextView hiScoreText = (TextView)findViewById(R.id.hiScore);
    		hiScoreText.setText(dualTiltHiScore + "");
    	}
    };
    
    private OnClickListener retryOnClickListener = new OnClickListener() {
    	public void onClick(View v) {
    		gameRunningLayout();
    		switch (gameType) {
    		case TILT: 
    			initGameThread(new TiltGameThread(CaveViewActivity.this));
    			break;
    		case CLASSIC:
    			initGameThread(new GameThread(CaveViewActivity.this));
    			touchHandler = caveTouchHandler;
    			break;
    		case DUAL_TILT:
    			renderer.cave = new DualCave();
    			initGameThread(new DualTiltGameThread(CaveViewActivity.this));
    		}
    		getPrefs();
    		renderer.cave.init();
        	mGLSurfaceView.requestRender();
        	System.gc();
    		gameThread.start();
    	}
    };
    
    private OnClickListener showScoresOnClickListener = new OnClickListener() {
		@Override
		public void onClick(View v) {
			simpleScores.setBoardId("cavedroid" + gameType.toString().toLowerCase());
			simpleScores.setPrivateKey(gameType.privateKey);
			
			simpleScores.submit(gameThread.score);
        	
        	TextView retryText = (TextView)findViewById(R.id.touchToRetry);
        	retryText.setText(R.string.loadingScores);
        	findViewById(R.id.hiScoreButton).setEnabled(false);
 
        	//TODO temporary hack, fix this
        	uiHandler.post(new Runnable() {
        		public void run() {
        			loadingScores = true;
        		}
        	});
		}
    };
    
    private OnClickListener mainMenuOnClickListener = new OnClickListener() {
		@Override
		public void onClick(View v) {
			gameStartLayout();
		}
    };
    
    private OnClickListener payOnClickListener = new OnClickListener() {
    	public void onClick(View v) {
    		Uri payUri = Uri.parse(DONATION_URL);
    		Intent payIntent = new Intent(Intent.ACTION_VIEW, payUri);
    		startActivity(payIntent);
    	}
    };
    
    private OnClickListener websiteOnClickListener = new OnClickListener() {
    	public void onClick(View v) {
    		Uri uri = Uri.parse(SITE_URL);
    		Intent intent = new Intent(Intent.ACTION_VIEW, uri);
    		startActivity(intent);
    	}
    };
    
    private OnClickListener settingsOnClickListener = new OnClickListener() {
    	public void onClick(View v) {
    		Intent settingsIntent = new Intent(getBaseContext(), Preferences.class);
    		startActivity(settingsIntent);
    	}
    };
    
    private OnClickListener hiScoresOnClickListener = new OnClickListener() {
    	public void onClick(View v) {
    		Resources res = getResources();
    		final CharSequence[] items = {res.getString(R.string.tiltModeButton), res.getString(R.string.classicModeButton), res.getString(R.string.dualTiltButton)};

    		AlertDialog.Builder builder = new AlertDialog.Builder(CaveViewActivity.this);
    		builder.setTitle("Game Type");
    		builder.setItems(items, new DialogInterface.OnClickListener() {
    		    public void onClick(DialogInterface dialog, int item) {
    		    	GameType game = GameType.TILT;
    		    	switch (item) {
    		    	case 0:
    		    		game = GameType.TILT;
    		    		break;
    		    	case 1:
    		    		game = GameType.CLASSIC;
    		    		break;
    		    	case 2:
    		    		game = GameType.DUAL_TILT;
    		    	}
    		    	simpleScores.setBoardId("cavedroid" + game.toString().toLowerCase());
    		    	simpleScores.setPrivateKey(game.privateKey);
    		    	simpleScores.show();
    		    }
    		});
    		builder.create().show();
    	}
    };
    
    public OnTouchListener onTouch = new OnTouchListener() {
    	
    	//Call whatever is currently handling touch
    	public boolean onTouch(View v, MotionEvent ev) {
    		touchHandler.touchMethod(ev.getAction());
    		try {
    			Thread.sleep(20); //Stop events from blocking
    		} catch (Exception e) {
    			e.printStackTrace();
    		}
    		return true;
    	}
    };
    
    public boolean onTrackballEvent(MotionEvent ev) {
    	return touchHandler.touchMethod(ev.getAction());
    }
    
    public boolean onKeyDown(int keyCode, KeyEvent ev) {
    	if (keyCode != KeyEvent.KEYCODE_BACK && keyCode != KeyEvent.KEYCODE_MENU) {
    		touchHandler.touchMethod(MotionEvent.ACTION_DOWN);
    		return true;
    	}
    	return super.onKeyDown(keyCode, ev);
    }
    
    public boolean onKeyUp(int keyCode, KeyEvent ev) {
    	if (keyCode != KeyEvent.KEYCODE_BACK && keyCode != KeyEvent.KEYCODE_MENU) {
    		touchHandler.touchMethod(MotionEvent.ACTION_UP);
    		return true;
    	}
    	return super.onKeyUp(keyCode, ev);
    }
    
    //Creates specific layout. TODO: Kinda chunky and disorganised, needs fixing.
    private void gameStartLayout() {
    	plusScore = (TextView) findViewById(R.id.plusScore);
    	
    	getPrefs();
    	renderer.cave = new Cave();
    	renderer.cave.init();
        
    	layout.replace(R.id.gameStart);
    	
    	layout.push(R.id.gameStartMain);
    	
    	layout.push(R.id.welcomeMain);
        
        mGLSurfaceView.requestRender();
        
        TextView retryText = (TextView)findViewById(R.id.touchToRetry);
		retryText.setText("");
    }
    
    private void gameRunningLayout() {
    	started = true;
	      
        layout.replace(R.id.inGame);
		
		scoreView.setText("0");
    }
    
    private void gameOverLayout() {        
        layout.replace(R.id.gameOver);
        touchHandler = nilTouchHandler;
        
        int thisHiScore;
        
        if (gameType == GameType.CLASSIC) {
        	thisHiScore = hiScore;
        } else {
        	thisHiScore = tiltHiScore;
        }
        
        TextView notification = (TextView)findViewById(R.id.touchToRetry);
        
        if (gameThread.score > thisHiScore) {
        	thisHiScore = gameThread.score;
        	
        	notification.setText(R.string.newHiScore);
        	
        	Editor prefsEditor = preferenceManager.edit();
        	
        	if (gameType == GameType.CLASSIC) {
        		prefsEditor.putInt("hiScore", thisHiScore);
        	} else {
        		prefsEditor.putInt("tiltHiScore", thisHiScore);
        	}
        	
        	prefsEditor.commit();
        } else {
        	notification.setText("");
        }
        
        TextView yourScore = (TextView)findViewById(R.id.yourScore);
        yourScore.setText(gameThread.score + "");
        
        TextView yourHiScore = (TextView)findViewById(R.id.yourHiScore);
        
        yourHiScore.setText(thisHiScore + "");
        
        
        DonationsText donationsText = (DonationsText) findViewById(R.id.donator);
        
        donationsText.newDonator();
        
        findViewById(R.id.hiScoreButton).setEnabled(true);
    }
    
    //Options menu stuff
    public boolean onCreateOptionsMenu(Menu menu) {
    	MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.options_menu, menu);
    	return true;
    }
    
    public boolean onPrepareOptionsMenu(Menu menu) {
    	onPause();
    	return true;
    }
    
    public void onOptionsMenuClosed(Menu menu) {
    	this.onResume();
    }
    
    public boolean onOptionsItemSelected(MenuItem item) {
    	switch (item.getItemId()) {
    	case R.id.settings: 
    		Intent settingsIntent = new Intent(getBaseContext(), Preferences.class);
    		startActivity(settingsIntent);
    		break;
    	case R.id.info:
    		Intent infoIntent = new Intent(getBaseContext(), Info.class);
    		startActivity(infoIntent);
    		break;
    	}
    	return true;
    }
}